package com.csx.governance.traffic.adapter.outbound.openfeign;


import com.csx.governance.traffic.core.context.TrafficContext;
import com.csx.governance.traffic.core.context.TrafficContextHolder;
import com.csx.governance.traffic.core.context.TrafficInternalContexts;
import com.csx.governance.traffic.core.context.TrafficRequest;
import com.csx.governance.traffic.core.context.openfeign.TrafficFeignRequest;
import com.csx.governance.traffic.core.context.openfeign.TrafficFeignResponse;
import com.csx.governance.traffic.core.interceptor.TrafficHandlerInterceptorRunner;
import feign.Client;
import feign.Request;
import feign.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * <p> traffic流量出口 - 适配Feign方式外调 </p>
 * @author cuisongxu
 * @date 2023/3/18 18:07
 */
public class TrafficFeignClient implements Client {

    private final Logger logger = LoggerFactory.getLogger(TrafficFeignClient.class);

    private final Client delegate;

    private final TrafficHandlerInterceptorRunner handlerInterceptorRunner;

    public TrafficFeignClient(Client delegate, TrafficHandlerInterceptorRunner handlerInterceptorRunner) {
        this.delegate = delegate;
        this.handlerInterceptorRunner = handlerInterceptorRunner;
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {

        TrafficFeignRequest trafficFeignRequest = new TrafficFeignRequest(request);
        TrafficFeignResponse trafficFeignResponse = null;
        Response response = null;
        Exception ex = null;
        // 构造请求上下文
        buildContext(trafficFeignRequest);
        try {
            handlerInterceptorRunner.preHandle(trafficFeignRequest, null);
            response = delegate.execute(request, options);
            trafficFeignResponse = new TrafficFeignResponse(response);
            handlerInterceptorRunner.postHandle(trafficFeignRequest, trafficFeignResponse);
        }catch (Exception e) {
            ex = e;
            logger.error("TrafficFeignClient execute error because: {}", e.getMessage());
        }finally {
            handlerInterceptorRunner.afterCompletion(trafficFeignRequest, trafficFeignResponse, ex);
        }
        return response;
    }

    private void buildContext(TrafficRequest request) {
        TrafficContext context = TrafficContextHolder.getContext();
        if(context != null) {
            context.setSubRequest(request);
        } else { // 说明是由内部定时任务发起的外调，而不是由入栈请求导致的外调
            TrafficInternalContexts.set(request);
        }
    }
}
